/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package states;

import entities.Bullet;
import entities.Enemy;
import entities.Panel;
import entities.PlayableChar;
import entities.TransitionObject;
import entities.Walls;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import management.ObjectDispatcher;
import management.DBAccess;
import management.ZoneBuilder;
import org.newdawn.slick.Animation;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Polygon;
import org.newdawn.slick.tiled.TiledMap;
import physics.BlockMap;
import physics.Physics;

public class GamePlayState extends BasicGameState {
    // Identificador del estat

    public static final int ID = 2;
    // Declaració de variables
    private PlayableChar player;
    private ArrayList<PlayableChar> players = new ArrayList<PlayableChar>();
    private ArrayList<Enemy> enemis = new ArrayList<Enemy>();
    private ArrayList<Bullet> bullets = new ArrayList<Bullet>();
    private ArrayList<TransitionObject> goes = new ArrayList<TransitionObject>();
    private ArrayList<Panel> panels = new ArrayList<Panel>();
    private ArrayList<Walls> walls = new ArrayList<Walls>();
    public BlockMap map;
    private float[] pos = new float[2];
    private Physics phys;
    private int cntSalt = 1;
    private boolean blocked = false;
    private Animation hud;
    private Animation life;
    private Animation energy;
    public TiledMap lastTmap;
    public DBAccess dba = new DBAccess();

    //finalització de la declaració de variables
    //
    @Override
    public int getID() {
        return ID;
    }

    //funció que s'executa quan crees el nou estar
    public void init(GameContainer gc, StateBasedGame sbg) throws SlickException {

        //asignació de variables
        ObjectDispatcher.setZone(1);
        hud = new Animation();
        hud.addFrame(new Image("resources/hud.png"), 2000);
        life = new Animation();
        life.addFrame(new Image("resources/life.png"), 2000);
        energy = new Animation();
        energy.addFrame(new Image("resources/energy.png"), 2000);
        map = ObjectDispatcher.getBlockMap();
        lastTmap = map.tmap;
        phys = new Physics();
        pos[0] = 0;
        pos[1] = 0;
        if (ObjectDispatcher.getPnjs().size() > 0) {
            players.add(ObjectDispatcher.getPnjs().get("Soldier"));
            players.add(ObjectDispatcher.getPnjs().get("BountyHunter"));
            players.add(ObjectDispatcher.getPnjs().get("Rogue"));
            players.add(ObjectDispatcher.getPnjs().get("Wolf"));
            player = players.get(0);
            player.setPosX(128);
            player.setPosY(BlockMap.mapHeight - 88);
        }
        enemis.add(ObjectDispatcher.getEnemies().get("EnemyA1"));
        enemis.get(0).setPosX(600);
        enemis.get(0).setPosY(500);
        enemis.add(ObjectDispatcher.getEnemies().get("EnemyA2"));
        enemis.get(1).setPosX(800);
        enemis.get(1).setPosY(500);
        enemis.add(ObjectDispatcher.getEnemies().get("EnemyA3"));
        enemis.get(2).setPosX(400);
        enemis.get(2).setPosY(40);
        enemis.add(ObjectDispatcher.getEnemies().get("EnemyA4"));
        enemis.get(3).setPosX(600);
        enemis.get(3).setPosY(40);
        enemis.add(ObjectDispatcher.getEnemies().get("EnemyA5"));
        enemis.get(4).setPosX(800);
        enemis.get(4).setPosY(20);
        goes = new ArrayList<TransitionObject>();
        goes.add(new TransitionObject());
        panels.add(new Panel());
        walls.add(new Walls());
        panels.get(0).setConnected(walls.get(0));
        //truca el metode que fa que la camara en mostri on es el personatje sense sortir-ne del mapa
        posicionarCamara();

        //Acaba la assignació de variables


        //zona para provar cosas mientras creo clases!!!!!!!!!!!11
//        //
//        hud = new Animation();
//        hud.addFrame(new Image("resources/hud.png"), 2000);
//        life = new Animation();
//        life.addFrame(new Image("resources/life.png"), 2000);
//        energy = new Animation();
//        energy.addFrame(new Image("resources/energy.png"), 2000);
//        map = new BlockMap("resources/begining.tmx");
//        pos[0] = 0;
//        pos[1] = 0;
//        player = new PlayableChar();
//        player.setPosX(128);
//        player.setPosY(BlockMap.mapHeight - 88);
//        player.setPoly(25, 40, 27, 71);
//        // player.setSaltable(true);
//        player.setParedSaltable(true);
//        player.setDoblesaltable(true);
//        player.setLife(100);
//        player.setMaxLife(100);
//        player.setEnergy(50);
//        player.setMaxEnergy(50);
//        npcs = new Enemy[3];
//        npcs[0] = new Enemy();
//        phys = new Physics();
//        npcs[0].setPosX(200);
//        npcs[0].setPosY(20);
//        npcs[0].setPoly(25, 40, 27, 71);
//        npcs[0].setSaltable(true);
//        npcs[0].setLife(60);
//        npcs[1] = new Enemy();
//        npcs[1].setPosX(300);
//        npcs[1].setPosY(20);
//        npcs[1].setPoly(25, 40, 27, 71);
//        npcs[1].setSaltable(true);
//        npcs[1].setLife(60);
//        npcs[2] = new Enemy();
//        npcs[2].setPosX(400);
//        npcs[2].setPosY(20);
//        npcs[2].setPoly(25, 40, 27, 71);
//        npcs[2].setSaltable(true);
//        npcs[2].setLife(60);
//        goes = new ArrayList<TransitionObject>();
//        goes.add(new TransitionObject());
//        panels.add(new Panel());
//        walls.add(new Walls());
//        panels.get(0).setConnected(walls.get(0));
//        posicionarCamara();
        //
        //
        //end zona
    }

    //metode que actualitza les animacions a la pantalla y truca als metodes de les clases Entity per tal de que es mostrin elles mateixes automaticament
    public void render(GameContainer gc, StateBasedGame sbg, Graphics grphcs) throws SlickException {
        //truca el metode que fa que la camara en mostri on es el personatje sense sortir-ne del mapas
        posicionarCamara();
        BlockMap.tmap.render((int) pos[0], (int) pos[1]); //renderitza el mapa en la pocició del personatge
        for (TransitionObject o : goes) { //recorrem la array d'objectes trancició per que es posin al seu lloc
            o.Render(gc, grphcs, (int) pos[0], (int) pos[1]); //renderitza els objectes trancició
        }
        for (Bullet b : bullets) { //recorrem la array de bales per que es posin al seu lloc
            b.Render(gc, grphcs, ((int) pos[0]), ((int) pos[1]));//renderitza totes les bales que hi ha en lloc
        }
        for (Panel pa : panels) { //recorrem la array de panells per que es posin al seu lloc
            pa.Render(gc, grphcs, ((int) pos[0]), ((int) pos[1])); //renderitza tots els bales que hi ha en lloc
        }
        for (Walls w : walls) { //recorrem la array de pareds per que es posin al seu lloc
            if (!w.isActivated()) { //si no estan activades les portes
                w.Render(gc, grphcs, ((int) pos[0]), ((int) pos[1])); //les renderitzem al seu lloc
            }
        }
        for (Enemy npcs : enemis) { //recorrem la array d'enemics per que es posin al seu lloc
            npcs.Render(gc, grphcs, ((int) pos[0]), ((int) pos[1])); //renderitzem els enemics per que es posin al seu lloc
        }
        player.Render(gc, grphcs, ((int) pos[0]), ((int) pos[1])); //renderitzem el personatge en joc on correspon
        int current = (player.getLife() * 83) / player.getMaxLife(); //
        for (int i = 0; i < current; i++) {
            grphcs.drawAnimation(life, 96 + (i * 7), 8);
        }
        int lvl = 1;
        int maxExp = 0;
        int minExp = 0;
        if (player.getExp() < 100) {
            lvl = 1;
            maxExp = 100;
            minExp = 0;
        } else if (player.getExp() < 200) {
            lvl = 2;
            maxExp = 200;
            minExp = 100;
        } else if (player.getExp() < 400) {
            lvl = 3;
            maxExp = 400;
            minExp = 200;
        } else if (player.getExp() < 700) {
            lvl = 4;
            maxExp = 700;
            minExp = 400;
        } else if (player.getExp() < 1000) {
            lvl = 5;
            maxExp = 1000;
            minExp = 700;
        } else if (player.getExp() < 1400) {
            lvl = 6;
            maxExp = 1400;
            minExp = 1000;
        } else if (player.getExp() < 1900) {
            lvl = 7;
            maxExp = 1900;
            minExp = 1400;
        } else if (player.getExp() < 2500) {
            lvl = 8;
            maxExp = 2500;
            minExp = 1900;
        } else if (player.getExp() < 3200) {
            lvl = 9;
            maxExp = 3200;
            minExp = 2500;
        } else {
            lvl = 10;
            maxExp = 4000;
            minExp = 3200;
        }
        int currentE = ((player.getExp() - minExp) * 42) / maxExp;
        if (currentE > maxExp) {
            currentE = maxExp;
        }
//        System.out.println(lvl);
        for (int i = 0; i < currentE; i++) {
            grphcs.drawAnimation(energy, 84 + (i * 7), 28);
        }
        grphcs.drawAnimation(hud, 0, 0);
    }

    public void update(GameContainer gc, StateBasedGame sbg, int i) throws SlickException {


        //comprueba si los personajes estan muertos o no
        if (player.isDead()) {
            float xx = player.getPosX();
            float yy = player.getPosY();
            boolean ll = player.isLeft();
            if (players.get(0).isDead() && players.get(1).isDead() && players.get(2).isDead() && players.get(3).isDead()) {
                sbg.enterState(GameOverState.ID);
            } else {
                player = playerDeadChange();
                player.setPosX(xx);
                player.setPosY(yy - 1);
                player.setLeft(ll);
            }
        }
        //final de comprobar los muertos


        //udate de comprovacion dercania pared
        Polygon poly = player.getPoly().copy();

        if (player.isParedSaltable()) {
            if (player.isLeft()) {
                poly.setX(poly.getX() - 2);
                if (phys.gentityCollisionWith(poly)) {
                    blocked = false;
                    player.setPared(true);
                }
            } else {
                poly.setX(poly.getX() + 2);
                if (phys.gentityCollisionWith(poly)) {
                    blocked = false;
                    player.setPared(true);
                }
            }
        }
        if (player.getVelY() == 0) {
            blocked = false;
        }
        //end udate de comprovacion dercania pared





        //liseners
        if (!player.isHurt()) {
            if (gc.getInput().isKeyPressed(Input.KEY_UP)) {
//            player.setPosX(100);
//            player.setPosY(20);
//            map = new BlockMap("resources/mapa02.tmx");
                for (TransitionObject o : goes) {
                    if (phys.entityToEntityCollision(player.getPoly(), o.getPoly())) {
                        o.goes(player);
//                        this.enter(gc, sbg);
                    }
                }
            }
            if (gc.getInput().isKeyPressed(Input.KEY_ESCAPE)) {
                sbg.enterState(MainMenuState.ID);
            }

            if (gc.getInput().isKeyDown(Input.KEY_LEFT)) {
                if (!blocked) {
                    player.setLeft(true);
                    player.setVelX(-1.6f);
                }
            }
            if (gc.getInput().isKeyDown(Input.KEY_RIGHT)) {
                if (!blocked) {
                    player.setLeft(false);
                    player.setVelX(1.6f);
                }
            }
            if (gc.getInput().isKeyDown(Input.KEY_DOWN)) {
                if (player.getVelY() == 0 && !player.isTransformable()) {
                    player.setDown(true);
                }
            }
            if (gc.getInput().isKeyPressed(Input.KEY_1)) {
                if (!players.get(0).isDead()) {
                    players.get(0).setPosX(player.getPosX());
                    players.get(0).setPosY(player.getPosY() - 1);
                    players.get(0).setLeft(player.isLeft());
                    player = players.get(0);
                }
            }
            if (gc.getInput().isKeyPressed(Input.KEY_2)) {
                if (!players.get(1).isDead()) {
                    players.get(1).setPosX(player.getPosX());
                    players.get(1).setPosY(player.getPosY() - 1);
                    players.get(1).setLeft(player.isLeft());
                    player = players.get(1);
                }
            }
            if (gc.getInput().isKeyPressed(Input.KEY_3)) {
                if (!players.get(2).isDead()) {
                    players.get(2).setPosX(player.getPosX());
                    players.get(2).setPosY(player.getPosY() - 1);
                    players.get(2).setLeft(player.isLeft());
                    player = players.get(2);
                }
            }
            if (gc.getInput().isKeyPressed(Input.KEY_4)) {
                if (!players.get(3).isDead()) {
                    players.get(3).setPosX(player.getPosX());
                    players.get(3).setPosY(player.getPosY() - 1);
                    players.get(3).setLeft(player.isLeft());
                    player = players.get(3);
                }
            }
            if (gc.getInput().isKeyPressed(Input.KEY_S)) {

                if (player.isSaltable()) {
                    player.setSaltable(false);
                    player.setVelY(-4.5f);
                    if (player.isDoblesaltable()) {
                        cntSalt = 1;
                    }
                } else if (player.isDoblesaltable() && cntSalt == 1) {
                    cntSalt = 0;
                    player.setVelY(-4f);
                }
                if (player.isParedSaltable() && player.getVelY() != -4.5f) {

                    if (player.isLeft()) {
                        poly.setX(poly.getX() - 1);
                        if (phys.gentityCollisionWith(poly)) {
                            player.setVelY(-3);
                            player.setSaltable(false);
                            player.setLeft(false);
                            player.setVelX(2);
                            blocked = true;
                        }
                    } else {
                        poly.setX(poly.getX() + 1);
                        if (phys.gentityCollisionWith(poly)) {
                            player.setVelY(-3);
                            player.setSaltable(false);
                            player.setLeft(true);
                            player.setVelX(-2);
                            blocked = true;
                        }
                    }
                }
            }
            if (gc.getInput().isKeyPressed(Input.KEY_W)) {
                if (!player.isTransformable()) {
                    player.setAtack(false);
                    player.setShoot(true);
                    if (player.isDown()) {
                        bullets.add(new Bullet(player.getPosX(), player.getPosY() + 53, true, player.isLeft()));
                    } else {
                        bullets.add(new Bullet(player.getPosX(), player.getPosY() + 38, true, player.isLeft()));
                    }
                }

            }
            if (gc.getInput().isKeyPressed(Input.KEY_D)) {
                player.setAtack(true);
                player.setShoot(false);
                for (Enemy npcs : enemis) {
                    if (!npcs.isDead()) {
                        if (phys.entityToEntityCollision(player.getAtackPoly(), npcs.getPoly())) {
                            npcs.setLife(npcs.getLife() - 10);
                            if (npcs.getLife() <= 0) {
                                player.setExp(player.getExp() + npcs.getExp());
                            }
                            npcs.setHurt(true);
                        }
                    }
                }
            }
            if (gc.getInput().isKeyPressed(Input.KEY_E)) {
                for (Panel pa : panels) {
                    if (phys.entityToEntityCollision(player.getPoly(), pa.getPoly())) {
                        pa.touch(player);
                    }
                }
            }
        }

        //end liseners

        player.Update(gc, i, phys);
        ArrayList<Bullet> del = new ArrayList<Bullet>();
        for (Bullet b : bullets) {
            if (!b.isPlayer()) {
                if (phys.entityToEntityCollision(player.getPoly(), b.getPoly())) {
                    player.setLife(player.getLife() - 5);
                    player.setHurt(true);
                    del.add(b);

                }
            }
        }
        for (Bullet d : del) {
            bullets.remove(d);
        }
        for (Walls w : walls) {
            w.Update(phys, player);
        }
        del = new ArrayList<Bullet>();
        for (Bullet b : bullets) {
            if (b.getPosX() > (-1 * pos[0]) && b.getPosX() < (-1 * pos[0]) + 800 && b.getPosY() > (-1 * pos[1]) && b.getPosY() < (-1 * pos[1]) + 600) {
                if (b.isLost()) {
                    del.add(b);
                }
                b.Update(gc, i, phys);

            } else {
                del.add(b);
            }
        }
        for (Enemy npcs : enemis) {
            if (npcs.getPosX() > (-1 * pos[0] - 45) && npcs.getPosX() < (-1 * pos[0] - 45) + 800 && npcs.getPosY() > (-1 * pos[1] - 47) && npcs.getPosY() < (-1 * pos[1] - 47) + 600) {
                npcs.Update(gc, i, phys, player, bullets);
                npcs.setEnPoly(player.getPoly());
                if (!npcs.isDead()) {
                    for (Bullet b : bullets) {
                        if (b.isPlayer()) {
                            if (phys.entityToEntityCollision(npcs.getPoly(), b.getPoly())) {
                                npcs.setLife(npcs.getLife() - 5);
                                if (npcs.getLife() <= 0) {
                                    player.setExp(player.getExp() + npcs.getExp());
                                }
                                npcs.setHurt(true);
                                del.add(b);

                            }
                        }
                    }
                }
            }
            for (Bullet d : del) {
                bullets.remove(d);
            }
        }
        if (!blocked) {
            player.setVelX(0);
        }
        for (Enemy npcs : enemis) {
            npcs.setVelX(0);
        }
        player.setDown(false);
        player.setPared(false);
    }

    public void posicionarCamara() {
        if (player.getPosX() > 800 / 2 - 45) {
            pos[0] = -(player.getPosX() - (800 / 2 - 45));
            if (pos[0] < -(BlockMap.mapWidth - 800)) {
                pos[0] = -(BlockMap.mapWidth - 800);
            }
        } else {
            pos[0] = 0;
        }
        if (player.getPosY() > 600 / 2 - 47) {
            pos[1] = -(player.getPosY() - (600 / 2 - 47));
            if (pos[1] < -(BlockMap.mapHeight - 600)) {
                pos[1] = -(BlockMap.mapHeight - 600);
            }

        } else {
            pos[1] = 0;

        }


    }

    public PlayableChar playerDeadChange() {
        for (PlayableChar p : players) {
            if (!p.isDead()) {
                return p;
            }
        }
        return null;
    }

    @Override
    public void enter(GameContainer gc, StateBasedGame sbg) {
        if (map.tmap != lastTmap) {
            players = new ArrayList<PlayableChar>();
            enemis = new ArrayList<Enemy>();
            bullets = new ArrayList<Bullet>();
            goes = new ArrayList<TransitionObject>();
            panels = new ArrayList<Panel>();
            walls = new ArrayList<Walls>();
            if (ObjectDispatcher.getPnjs().size() > 0) {
                players.add(ObjectDispatcher.getPnjs().get("Soldier"));
                players.add(ObjectDispatcher.getPnjs().get("BountyHunter"));
                players.add(ObjectDispatcher.getPnjs().get("Rogue"));
                players.add(ObjectDispatcher.getPnjs().get("Wolf"));
            }
            if (ObjectDispatcher.getZone() == 1) {
//                 player = players.get(0);
                player.setPosX(128);
                player.setPosY(BlockMap.mapHeight - 88);
            }
            enemis.add(ObjectDispatcher.getEnemies().get("EnemyA1"));
            enemis.get(0).setPosX(600);
            enemis.get(0).setPosY(500);
            enemis.add(ObjectDispatcher.getEnemies().get("EnemyA2"));
            enemis.get(1).setPosX(800);
            enemis.get(1).setPosY(500);
            enemis.add(ObjectDispatcher.getEnemies().get("EnemyA3"));
            enemis.get(2).setPosX(400);
            enemis.get(2).setPosY(40);
            enemis.add(ObjectDispatcher.getEnemies().get("EnemyA4"));
            enemis.get(3).setPosX(600);
            enemis.get(3).setPosY(40);
            enemis.add(ObjectDispatcher.getEnemies().get("EnemyA5"));
            enemis.get(4).setPosX(800);
            enemis.get(4).setPosY(20);
            goes.add(new TransitionObject());
            panels.add(new Panel());
            walls.add(new Walls());
            panels.get(0).setConnected(walls.get(0));
        } else if (ObjectDispatcher.getZone() == 2) {
            //player = players.get(0);
            player.setPosX(128);
            player.setPosY(BlockMap.mapHeight - 88);
            enemis.add(ObjectDispatcher.getEnemies().get("EnemyA1"));
            enemis.get(0).setPosX(200);
            enemis.get(0).setPosY(20);
            enemis.add(ObjectDispatcher.getEnemies().get("EnemyA2"));
            enemis.get(1).setPosX(300);
            enemis.get(1).setPosY(20);
            enemis.add(ObjectDispatcher.getEnemies().get("EnemyA3"));
            enemis.get(2).setPosX(400);
            enemis.get(2).setPosY(20);
        }
        int zone = ObjectDispatcher.getZone();
        int expPnj1 = players.get(0).getExp();
        int expPnj2 = players.get(1).getExp();
        int expPnj3 = players.get(2).getExp();
        int expPnj4 = players.get(3).getExp();
        int idPartida = ObjectDispatcher.idPartida;
        if (idPartida != 0) {
            dba.ActualitzarPartida(zone, expPnj1, expPnj2, expPnj3, expPnj4, idPartida);
        } else {
            dba.GuardarPartidaNova(zone, expPnj1, expPnj2, expPnj3, expPnj4);
        }
        lastTmap = map.tmap;
    }
}
